using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    /// <summary>
    /// 用户仓储实现
    /// </summary>
    public class UserRepository : Repository<User>, IUserRepository
    {
        public UserRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<User?> GetByUsernameAsync(string username)
        {
            return await _dbSet.FirstOrDefaultAsync(u => u.Username == username);
        }

        public async Task<User?> GetByEmailAsync(string email)
        {
            return await _dbSet.FirstOrDefaultAsync(u => u.Email == email);
        }

        public async Task<User?> GetByPhoneNumberAsync(string phoneNumber)
        {
            return await _dbSet.FirstOrDefaultAsync(u => u.PhoneNumber == phoneNumber);
        }

        public async Task<IEnumerable<User>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet.Where(u => u.LifeStage == lifeStage).ToListAsync();
        }

        public async Task<IEnumerable<User>> GetByCreatedDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(u => u.CreatedAt >= startDate && u.CreatedAt <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<User>> GetByLastLoginDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(u => u.LastLoginAt >= startDate && u.LastLoginAt <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<User>> GetActiveUsersAsync()
        {
            return await _dbSet.Where(u => u.IsActive).ToListAsync();
        }

        public async Task<IEnumerable<User>> GetInactiveUsersAsync()
        {
            return await _dbSet.Where(u => !u.IsActive).ToListAsync();
        }

        public async Task<int> GetTotalCountAsync()
        {
            return await _dbSet.CountAsync();
        }

        public async Task<int> GetActiveCountAsync()
        {
            return await _dbSet.CountAsync(u => u.IsActive);
        }

        public async Task<IEnumerable<User>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(u => u.CreatedAt >= startDate && u.CreatedAt <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<User>> GetActiveByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(u => u.IsActive && u.CreatedAt >= startDate && u.CreatedAt <= endDate).ToListAsync();
        }
    }

    /// <summary>
    /// 生理周期仓储实现
    /// </summary>
    public class MenstrualCycleRepository : Repository<MenstrualCycle>, IMenstrualCycleRepository
    {
        public MenstrualCycleRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<MenstrualCycle>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId).OrderByDescending(c => c.StartDate).ToListAsync();
        }

        public async Task<MenstrualCycle?> GetLatestByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId).OrderByDescending(c => c.StartDate).FirstOrDefaultAsync();
        }

        public async Task<IEnumerable<MenstrualCycle>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(c => c.UserId == userId && c.StartDate >= startDate && c.StartDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualCycle>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(c => c.StartDate >= startDate && c.StartDate <= endDate).ToListAsync();
        }

        public async Task<MenstrualCycle?> GetPredictedCycleByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId && c.IsPredicted).OrderByDescending(c => c.StartDate).FirstOrDefaultAsync();
        }

        public async Task<bool> IsCycleExistsForDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.AnyAsync(c => c.UserId == userId && 
                ((c.StartDate >= startDate && c.StartDate <= endDate) || 
                 (c.EndDate >= startDate && c.EndDate <= endDate) ||
                 (c.StartDate <= startDate && c.EndDate >= endDate)));
        }

        public async Task<int> GetAverageCycleLengthAsync(Guid userId)
        {
            var cycles = await _dbSet.Where(c => c.UserId == userId && !c.IsPredicted).ToListAsync();
            if (cycles.Count < 2)
                return 0;

            var totalDays = 0;
            for (int i = 1; i < cycles.Count; i++)
            {
                totalDays += (cycles[i - 1].StartDate - cycles[i].StartDate).Days;
            }

            return totalDays / (cycles.Count - 1);
        }

        public async Task<int> GetAveragePeriodLengthAsync(Guid userId)
        {
            var cycles = await _dbSet.Where(c => c.UserId == userId && !c.IsPredicted).ToListAsync();
            if (!cycles.Any())
                return 0;

            return (int)cycles.Average(c => (c.EndDate - c.StartDate).Days);
        }
    }

    /// <summary>
    /// 生理症状仓储实现
    /// </summary>
    public class MenstrualSymptomRepository : Repository<MenstrualSymptom>, IMenstrualSymptomRepository
    {
        public MenstrualSymptomRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<MenstrualSymptom>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(s => s.UserId == userId).OrderByDescending(s => s.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualSymptom>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(s => s.UserId == userId && s.RecordDate >= startDate && s.RecordDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualSymptom>> GetBySymptomTypeAsync(Guid userId, string symptomType)
        {
            return await _dbSet.Where(s => s.UserId == userId && s.SymptomType == symptomType).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualSymptom>> GetByCycleIdAsync(Guid cycleId)
        {
            return await _dbSet.Where(s => s.CycleId == cycleId).ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetSymptomStatisticsByUserIdAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var symptoms = await _dbSet
                .Where(s => s.UserId == userId && s.RecordDate >= startDate && s.RecordDate <= endDate)
                .GroupBy(s => s.SymptomType)
                .Select(g => new { SymptomType = g.Key, Count = g.Count() })
                .ToListAsync();

            return symptoms.ToDictionary(s => s.SymptomType, s => s.Count);
        }
    }

    /// <summary>
    /// 生理笔记仓储实现
    /// </summary>
    public class MenstrualNoteRepository : Repository<MenstrualNote>, IMenstrualNoteRepository
    {
        public MenstrualNoteRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<MenstrualNote>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(n => n.UserId == userId).OrderByDescending(n => n.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualNote>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(n => n.UserId == userId && n.RecordDate >= startDate && n.RecordDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualNote>> GetByCycleIdAsync(Guid cycleId)
        {
            return await _dbSet.Where(n => n.CycleId == cycleId).ToListAsync();
        }

        public async Task<IEnumerable<MenstrualNote>> GetByTagAsync(Guid userId, string tag)
        {
            return await _dbSet.Where(n => n.UserId == userId && n.Tags.Contains(tag)).ToListAsync();
        }
    }

    /// <summary>
    /// 基础体温仓储实现
    /// </summary>
    public class BasalBodyTemperatureRepository : Repository<BasalBodyTemperature>, IBasalBodyTemperatureRepository
    {
        public BasalBodyTemperatureRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<BasalBodyTemperature>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(t => t.UserId == userId).OrderByDescending(t => t.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<BasalBodyTemperature>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(t => t.UserId == userId && t.RecordDate >= startDate && t.RecordDate <= endDate).ToListAsync();
        }

        public async Task<BasalBodyTemperature?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(t => t.UserId == userId && t.RecordDate.Date == date.Date);
        }

        public async Task<IEnumerable<BasalBodyTemperature>> GetLatestByUserIdAsync(Guid userId, int count = 7)
        {
            return await _dbSet.Where(t => t.UserId == userId).OrderByDescending(t => t.RecordDate).Take(count).ToListAsync();
        }

        public async Task<double> GetAverageTemperatureAsync(Guid userId, int days = 7)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var temperatures = await _dbSet
                .Where(t => t.UserId == userId && t.RecordDate >= startDate && t.RecordDate <= endDate)
                .ToListAsync();

            return temperatures.Any() ? temperatures.Average(t => t.Temperature) : 0;
        }

        public async Task<double> GetTemperatureVariationAsync(Guid userId, int days = 7)
        {
            var temperatures = await GetLatestByUserIdAsync(userId, days);
            if (temperatures.Count() < 2)
                return 0;

            var avgTemp = await GetAverageTemperatureAsync(userId, days);
            var sumOfSquares = temperatures.Sum(t => Math.Pow(t.Temperature - avgTemp, 2));
            return Math.Sqrt(sumOfSquares / temperatures.Count());
        }
    }
}